# -*- coding: utf-8 -*-
''' @author: Dinh Manh Dau <dinhmanhdau@gmail.com>
'''
import pycommonlib as clib
import workerpool
import traceback
import datetime, time
import re, os

from pymongo import Connection
from termcolor  import cprint

LOCAL_PATH          = '/home/hoangnamhai/HarvestedData/tintuc/news'
MONGO_SERVER        = 'beta.mana.vn'   
MONGO_PORT          = 27017
DATABASE            = 'tintuc_v2'
PREFIX              = '/uploads/news' 
SITE_URL            = 'http://m.kenh14.vn'
MAX_COUNT           = 20
MAX_ARTICLE         = 90
MAX_PAGE            = 20
os.umask(0000)

class Kenh14():
    CATEGORIES = { 
       'star':       {'link' : 'c0s1/ngoi-sao.htm',   'category': unicode('Giải trí', 'utf-8'), 'tags': ['giai tri']},
       'phim-anh':   {'link' : 'c0s2/phim-anh.htm',   'category': unicode('Giải trí', 'utf-8'), 'tags': ['phim anh', 'dien anh', 'giai tri']},
       'am-nhac':    {'link' : 'c0s3/am-nhac.htm',    'category': unicode('Giải trí', 'utf-8'), 'tags': ['am nhac', 'dien anh', 'giai tri']},
       'hoc-duong':  {'link' : 'c0s47/hoc-duong.htm', 'category': unicode('Giáo dục', 'utf-8'), 'tags': ['giao duc']},
       'the-thao':   {'link' : 'c0s118/the-thao.htm', 'category': unicode('Thể thao', 'utf-8'),  'tags': ['the thao']},
       'chuyen-la':  {'link' : 'c0s44/chuyen-la.htm', 'category': unicode('Chuyện lạ', 'utf-8'),        'tags': ['chuyen la', 'fun']},
       'doi-song':   {'link' : 'c0s4/doi-song.htm',   'category': unicode('Văn hóa - Xã hội', 'utf-8'), 'tags': ['doi song', 'xa hoi']},
       'cong-nghe':  {'link' : 'c0s31/cong-nghe.htm', 'category': unicode('Công nghệ số', 'utf-8'),     'tags': ['cntt', 'cong nghe so']},
       'thoi-trang': {'link' : 'c0s5/thoi-trang.htm', 'category': unicode('Làm đẹp - Thời trang', 'utf-8'), 'tags': ['thoi trang', 'fashion']},
       'qua-tang':   {'link' : 'c0s38/qua-tang.htm',  'category': unicode('Làm đẹp - Thời trang', 'utf-8'), 'tags': ['qua tang', 'thoi trang']},
       'kheo-tay':   {'link' : 'c0s33/kheo-tay.htm',  'category': unicode('Sức khỏe - Giới tính', 'utf-8'), 'tags': ['kheo tay']},       
       'gioi-tinh':  {'link' : 'c0s79/gioi-tinh.htm', 'category': unicode('Sức khỏe - Giới tính', 'utf-8'), 'tags': ['gioi tinh', 'tinh yeu']}, 
    }
    def __init__(self, server, port, database):
        CONNECT             = Connection(server, port)
        self.DB             = CONNECT[database]
    
    def getRootLftCategory(self, name):
        try:
            collection = self.DB['category']
            if name==None or name=='': return None, None 
            root        =   collection.find_one({'data': 'Tin tức'}, {'root_id': 1})
            if root==None: 
                result  =   collection.find_one({'data': name}, {'root_id': 1, 'lft': 1})
            else:  
                result  =   collection.find_one({'data': name, 'root_id': root['root_id']}, {'root_id': 1, 'lft': 1})
            if result==None: cprint('Category chưa tồn tại !', 'red'); return None, None
            else: return result['root_id'], result['lft']
        except:
            traceback.print_exc()
    
    def getDatetime(self, text):
       try:
           result = datetime.datetime.utcnow()
           if text==None or text=='': return result
           m        =   clib.regexString('(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)', text)
           if m:
               year = int(float(m.group(3))); month  = int(float(m.group(1))); day    = int(float(m.group(2)))
               hour = int(float(m.group(4))); minute = int(float(m.group(5))); second = int(float(m.group(6))) 
               return datetime.datetime(year, month, day, hour, minute, second) + datetime.timedelta(seconds=time.timezone)
           return result
       except:
           traceback.print_exc()
    
    def checkArticleDuplicate(self, link):
        ''' Kiểm tra trùng tin tức trong DB, trả vê 1 nếu trùng, 0 trong trường hợp ngược lại
        ''' 
        try:
            collection  =  self.DB['article']
            if link==None or link=='': return None, None
            m           =   clib.regexString('/([a-z0-9]{1,3})/(\w+)-(\d+)/', link)
            if m: aId   =   '{0}{1}-{2}'.format(m.group(1), m.group(2), m.group(3)) 
            else: aId   =   clib.getMd5(link)   
            result      =   collection.find_one({'hashUrl' : aId})
            if result!=None:  cprint('Tin tức đã tồn tại trong cơ sở dữ liệu', 'red'); return 1, aId
            return 0, aId 
        except:
            traceback.print_exc()
            return None, None
    
    def processArticle(self, link, cat):
        ''' Hàm xử lý chi tiết một tin tức, nếu tin đã tồn tại trong DB thì trả về: 1, ngược lại: 0
        '''
        try:
            if link==None or link=='': return
            root_id, lft    = self.getRootLftCategory(self.CATEGORIES[cat]['category'])
            if root_id==None: return
            tags = self.CATEGORIES[cat]['tags']
            check_exists, aId    =   self.checkArticleDuplicate(link)
            if check_exists==1: return 1
            print ('----------------------------------------------------------------------')
            cprint('Process article: ' + link, 'yellow')            
            title = thumbnail = description = ''; data = []; flgImg = False 
            tree            =   clib.getXMLTree(link)
            contentNode     =   tree.xpath('//div[@class="wrapper"]/div[@class="detail"]') 
            if len(contentNode) <= 0: cprint('Tin có cấu trúc khác, không thể lấy được nội dung', 'red'); return
            primaryNode     =   contentNode[0]
            titleNode       =   primaryNode.xpath('.//h1')
            if len(titleNode) > 0:  title = clib.getStringWithNode(titleNode[0]); titleNode[0].getparent().remove(titleNode[0])
            dateNode        =   primaryNode.xpath('.//p[@class="detail_date"]')
            if len(dateNode) > 0:   
                postedDate  =  self.getDatetime(clib.getStringWithNode(dateNode[0]))
                dateNode[0].getparent().remove(dateNode[0])
            introNode       =   primaryNode.xpath('.//p[@class="detail_sapo"]')
            if len(introNode) > 0:  description = clib.getStringWithNode(introNode[0]); introNode[0].getparent().remove(introNode[0])
            # remove all tag style and script
            listStyle       =   primaryNode.xpath('.//style')
            if len(listStyle) > 0:
                for style in listStyle: style.getparent().remove(style)
            listScript      =   primaryNode.xpath('.//script')
            if len(listScript) > 0:
                for script in listScript: script.getparent().remove(script)
            listLink        =   primaryNode.xpath('.//ul[@class="detail_lastnews"]')
            if len(listLink) > 0:
                for item in listLink:   item.getparent().remove(item)
            listNode        =   primaryNode.xpath('./*')
            if len(listNode) > 0:
                for node in listNode:
                    if node.tag in ['style', 'script']: continue
                    imgNode     =   node.xpath('.//img')
                    if len(imgNode) > 0:
                        text        =   clib.getStringWithNode(node)
                        #linkImage   =   '{0}{1}'.format(SITE_URL, imgNode[0].get('src'))
                        linkImage   = imgNode[0].get('src')
                        if linkImage!=None and linkImage!='':
                            result, source, img_name, size = clib.saveImage(linkImage, PREFIX, LOCAL_PATH)
                            if result!=None:
                                if flgImg==False: thumbnail = source; flgImg = True
                                data.append({'data': source, 'type': 'image', 'caption': text})
                                cprint('Source image : ' +  source, 'yellow'); print 'Caption :', text
                    else:
                        content     =   clib.getStringWithNode(node)
                        if content!=None and len(content)>1:
                             data.append({'data': content, 'type': 'text'}); cprint(content, 'green') 
                        if node.tail:   
                            contentTail = node.tail.strip(); contentTail = ' '.join(contentTail.split())
                            if len(contentTail) > 1: data.append({'data': contentTail, 'type': 'text'}); print 'Tail :', contentTail
                            
            doc = ({ 'hashUrl'       :   aId,
                    'title'         :   title,
                    'thumbnail'     :   thumbnail,
                    'description'   :   description,
                    'content'       :   data,
                    'newsLink'      :   link,
                    'update'        :   postedDate,
                    'source'        :   'kenh14.vn',
                    'category'      :   lft,
                    'root'          :   root_id,
                    'is_active'     :   True,
                    'lastupdate'    :   datetime.datetime.utcnow(),
                    'timestamp'     :   time.time(),
                    'date'          :   datetime.datetime.utcnow(),
                    'tags'          :   tags, })
            collection  = self.DB['article']
            if len(data) > 0: 
                if len(data)==1: 
                    if data[0]['type'] != 'image': collection.save(doc)
                else: collection.save(doc)
            else: cprint('XPath không đúng, không thể lấy được nội dung của tin.', 'red')
            print postedDate
            print aId
            cprint('Title :' + title, 'green')
            cprint('Thumbnail : ' + thumbnail, 'green')
            cprint('Intro : ' + description, 'green')
            return 0
        except:
            traceback.print_exc()        
            
    def processPage(self, page, cat):
        try:
            gbcount     = loop = 0 
            lurl        =   '{0}/{1}/trang-{2}.htm'.format(SITE_URL, self.CATEGORIES[cat]['link'], page)
            cprint('Process page : ' + lurl, 'yellow')
            tree        =   clib.getXMLTree(lurl)
            listNode    =   tree.xpath('//div[@class="wrapper"]/div[@class="content"]/div/a')
            if len(listNode) < 1: return
            for node in listNode:  
                count = self.processArticle('{0}{1}'.format(SITE_URL, node.get('href')), cat)
                if count!=None: gbcount += count; loop += 1
            return gbcount, loop
        except:
            traceback.print_exc(); return None, None
            
    def processCategory(self, cat):
        try:
            gbcount = 0; loop = 0
            cprint('Process category : ' + self.CATEGORIES[cat]['link'], 'yellow')
            lurl = '{0}/{1}.htm'.format(SITE_URL, self.CATEGORIES[cat]['link'])
            for page in range(1, MAX_PAGE):
                print 'COUNT, LOOP : (', gbcount, ', ', loop, ')' 
                if gbcount>MAX_COUNT or loop>MAX_ARTICLE:
                    cprint('Dừng xử lý do vượt quá số lượng trùng lặp cho phép hoặc vượt quá số lượng tin cần lấy.')
                    return 
                c, l = self.processPage(page, cat)
                if c!=None: gbcount += c; loop += l
        except:
            traceback.print_exc()

def forceQuit():
    try:
        print 'Finished.', datetime.datetime.now()
        pid = os.getpid(); os._exit(1); os.kill(pid, 9)
    except:
        traceback.print_exc()
        
if __name__ == '__main__':
    try:
        cprint('start crawler m.kenh14.vn', 'yellow')
        crawler = Kenh14(MONGO_SERVER, MONGO_PORT, DATABASE)
        pool = workerpool.WorkerPool(size=5)
        pool.map(crawler.processCategory, crawler.CATEGORIES.keys())
        pool.shutdown(); pool.wait()
        forceQuit()
    except:
        traceback.print_exc()
